﻿namespace Microsoft.SharePoint.Client
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Runtime.CompilerServices;
    using System.Text;

    public class ClientContext : ClientRuntimeContext
    {
        private FormDigestInfo m_formDigestInfo;
        private Microsoft.SharePoint.Client.Site m_site;
        private Microsoft.SharePoint.Client.Web m_web;
        private static bool s_addedScriptTypeAssembly;
        private static ClientContext s_current;

        public ClientContext(string webFullUrl) : base(webFullUrl)
        {
        }

        public ClientContext(Uri webFullUrl) : base((webFullUrl == null) ? null : webFullUrl.ToString())
        {
        }

        private void BuildGetUpdatedFormDigestInfoRequestBody(Stream requestStream)
        {
            TextWriter writer = new StreamWriter(requestStream, Encoding.UTF8);
            writer.Write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n  <soap:Body>\r\n    <GetUpdatedFormDigestInformation xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\" />\r\n  </soap:Body>\r\n</soap:Envelope>");
            writer.Flush();
        }

        public override void ExecuteQueryAsync(ClientRequestSucceededEventHandler succeededCallback, ClientRequestFailedEventHandler failedCallback)
        {
            if (!s_addedScriptTypeAssembly)
            {
                s_addedScriptTypeAssembly = true;
                ClientRuntimeContext.AddClientTypeAssembly(typeof(ClientContext).Assembly);
            }
            try
            {
                if (((this.m_formDigestInfo == null) && (ApplicationContext.Current != null)) && ((string.Compare(ApplicationContext.Current.Url, base.Url, StringComparison.OrdinalIgnoreCase) == 0) && !string.IsNullOrEmpty(ApplicationContext.Current.FormDigest)))
                {
                    this.m_formDigestInfo = new FormDigestInfo();
                    this.m_formDigestInfo.DigestValue = ApplicationContext.Current.FormDigest;
                    this.m_formDigestInfo.Expiration = ApplicationContext.Current.FormDigestExpiration;
                }
                if ((this.m_formDigestInfo != null) && (this.m_formDigestInfo.Expiration > DateTime.UtcNow))
                {
                    base.PendingRequest.WebRequest.Headers["X-RequestDigest"] = this.m_formDigestInfo.DigestValue;
                    base.ExecuteQueryAsync(succeededCallback, failedCallback);
                }
                else
                {
                    HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(new Uri(this.GetSitesAsmxUrl()));
                    this.FireExecutingWebRequestEventInternal(new WebRequestEventArgs(webRequest));
                    webRequest.ContentType = "text/xml";
                    webRequest.Method = "POST";
                    if ((ApplicationContext.Current != null) && !string.IsNullOrEmpty(ApplicationContext.Current.RequestToken))
                    {
                        webRequest.Headers["X-RequestToken"] = ApplicationContext.Current.RequestToken;
                    }
                    ClientRequest clientRequest = base.SetPendingRequestToBeExecuted();
                    webRequest.BeginGetRequestStream(new AsyncCallback(this.OnGetRequestStream), new AsyncRequestState(succeededCallback, failedCallback, webRequest, clientRequest));
                }
            }
            catch (Exception exception)
            {
                if (failedCallback != null)
                {
                    failedCallback(this, new ClientRequestFailedEventArgs(base.PendingRequest, exception));
                }
            }
        }

        internal void FireExecutingWebRequestEventInternal(WebRequestEventArgs args)
        {
            this.OnExecutingWebRequest(args);
        }

        private string GetSitesAsmxUrl()
        {
            string url = base.Url;
            if (!url.EndsWith("/"))
            {
                url = url + "/";
            }
            url = url + "_vti_bin/sites.asmx";
            if ((ApplicationContext.Current != null) && (string.Compare(ApplicationContext.Current.Url, base.Url, StringComparison.OrdinalIgnoreCase) == 0))
            {
                url = ApplicationContext.Current.GetRequestUrl(url);
            }
            return url;
        }

        private string GetValueFromResponse(string response, string beginTag, string endTag)
        {
            int index = response.IndexOf(beginTag);
            if (index < 0)
            {
                return null;
            }
            index += beginTag.Length;
            int num2 = response.IndexOf(endTag);
            if (num2 < 0)
            {
                return null;
            }
            if (index > num2)
            {
                return null;
            }
            return response.Substring(index, num2 - index);
        }

        private void OnGetRequestStream(IAsyncResult asyncResult)
        {
            AsyncRequestState asyncState = (AsyncRequestState) asyncResult.AsyncState;
            try
            {
                using (Stream stream = asyncState.WebRequest.EndGetRequestStream(asyncResult))
                {
                    this.BuildGetUpdatedFormDigestInfoRequestBody(stream);
                }
                asyncState.WebRequest.BeginGetResponse(new AsyncCallback(this.OnGetResponse), asyncState);
            }
            catch (Exception exception)
            {
                if (asyncState.FailedCallback != null)
                {
                    asyncState.FailedCallback(this, new ClientRequestFailedEventArgs(base.PendingRequest, exception));
                }
            }
        }

        private void OnGetResponse(IAsyncResult asyncResult)
        {
            AsyncRequestState asyncState = (AsyncRequestState) asyncResult.AsyncState;
            try
            {
                HttpWebResponse response = (HttpWebResponse) asyncState.WebRequest.EndGetResponse(asyncResult);
                if ((response.StatusCode != HttpStatusCode.OK) || (response.ContentType.ToLower(CultureInfo.InvariantCulture).IndexOf("text/xml") < 0))
                {
                    throw new ClientRequestException(Resources.GetString("CannotContactSite", new object[] { base.Url }));
                }
                FormDigestInfo info = this.ParseFormDigest(response.GetResponseStream());
                if (info == null)
                {
                    throw new ClientRequestException(Resources.GetString("CannotContactSite", new object[] { base.Url }));
                }
                this.m_formDigestInfo = info;
                asyncState.ClientRequest.WebRequest.Headers["X-RequestDigest"] = this.m_formDigestInfo.DigestValue;
                base.ExecuteQueryAsync(asyncState.ClientRequest, asyncState.SucceededCallback, asyncState.FailedCallback);
            }
            catch (Exception exception)
            {
                if (asyncState.FailedCallback != null)
                {
                    asyncState.FailedCallback(this, new ClientRequestFailedEventArgs(base.PendingRequest, exception));
                }
            }
        }

        private FormDigestInfo ParseFormDigest(Stream responseStream)
        {
            string response = new StreamReader(responseStream).ReadToEnd();
            string str2 = this.GetValueFromResponse(response, "<DigestValue>", "</DigestValue>");
            string s = this.GetValueFromResponse(response, "<TimeoutSeconds>", "</TimeoutSeconds>");
            if ((str2 == null) || (s == null))
            {
                return null;
            }
            int num = int.Parse(s);
            return new FormDigestInfo { DigestValue = str2, Expiration = DateTime.UtcNow.AddSeconds(num * 0.75) };
        }

        public static ClientContext Current
        {
            get
            {
                if (s_current == null)
                {
                    string url = null;
                    if (ApplicationContext.Current == null)
                    {
                        ApplicationContext.Init(null);
                    }
                    if ((ApplicationContext.Current != null) && !string.IsNullOrEmpty(ApplicationContext.Current.Url))
                    {
                        url = ApplicationContext.Current.Url;
                    }
                    if (!string.IsNullOrEmpty(url))
                    {
                        s_current = new ClientContext(url);
                    }
                }
                return s_current;
            }
        }

        public Version ServerVersion
        {
            get
            {
                return base.ServerLibraryVersion;
            }
        }

        public Microsoft.SharePoint.Client.Site Site
        {
            get
            {
                if (this.m_site == null)
                {
                    RequestContext current = RequestContext.GetCurrent(this);
                    this.m_site = current.Site;
                }
                return this.m_site;
            }
        }

        public Microsoft.SharePoint.Client.Web Web
        {
            get
            {
                if (this.m_web == null)
                {
                    RequestContext current = RequestContext.GetCurrent(this);
                    this.m_web = current.Web;
                }
                return this.m_web;
            }
        }

        private class AsyncRequestState
        {
            private Microsoft.SharePoint.Client.ClientRequest m_clientRequest;
            private ClientRequestFailedEventHandler m_failedCallback;
            private ClientRequestSucceededEventHandler m_succeededCallback;
            private HttpWebRequest m_webRequest;

            public AsyncRequestState(ClientRequestSucceededEventHandler succeededCallback, ClientRequestFailedEventHandler failedCallback, HttpWebRequest webRequest, Microsoft.SharePoint.Client.ClientRequest clientRequest)
            {
                this.m_succeededCallback = succeededCallback;
                this.m_failedCallback = failedCallback;
                this.m_webRequest = webRequest;
                this.m_clientRequest = clientRequest;
            }

            public Microsoft.SharePoint.Client.ClientRequest ClientRequest
            {
                get
                {
                    return this.m_clientRequest;
                }
            }

            public ClientRequestFailedEventHandler FailedCallback
            {
                get
                {
                    return this.m_failedCallback;
                }
            }

            public ClientRequestSucceededEventHandler SucceededCallback
            {
                get
                {
                    return this.m_succeededCallback;
                }
            }

            public HttpWebRequest WebRequest
            {
                get
                {
                    return this.m_webRequest;
                }
            }
        }

        private class FormDigestInfo
        {
            public string DigestValue { get; set; }

            public DateTime Expiration { get; set; }
        }
    }
}

